#include <stdio.h>
#include "key.h"
#include "systick.h"
#include "i2c.h"
#include "hal_i2c.h"
#include "clock_init.h"
#include "msa311.h"

#define APP_I2C_TARGET_ADDR  0x62u
#define APP_I2C_TIMEOUT_TIME 3000u  /* Wait for the time when the status flag appears. If exceeds time, don't wait any longer and return to timeout. */
static  I2C_MasterXfer_Type app_i2c_xfer;

void BOARD_I2C1_Init(void)
{
#if I2C_MODE == USE_HARD_I2C    
    GPIO_Init_Type gpio_init;
    /* PC6 - I2C1_SCL. */
    gpio_init.Pins  = GPIO_PIN_6;
    gpio_init.PinMode  = GPIO_PinMode_AF_OpenDrain;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &gpio_init);
    GPIO_PinAFConf(GPIOC, gpio_init.Pins, GPIO_AF_4);

    /* PC7 - I2C1_SDA. */
    gpio_init.Pins  = GPIO_PIN_7;
    gpio_init.PinMode  = GPIO_PinMode_AF_OpenDrain;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &gpio_init);
    GPIO_PinAFConf(GPIOC, gpio_init.Pins, GPIO_AF_4);

    /* Setup I2C initialization values. */
    I2C_Master_Init_Type i2c_init;
    i2c_init.ClockFreqHz = CLOCK_APB1_FREQ;
    i2c_init.BaudRate = I2C_BaudRate_100K;

    /* Initialize I2C master. */
    I2C_InitMaster(I2C1, &i2c_init);

    /* The target device address needs to be configured before enabling. */
    I2C_SetTargetAddr(I2C1, MSA311_I2CADDR_DEFAULT_7);

    /* Enable I2C. */
    I2C_Enable(I2C1, true);

#elif I2C_MODE == USER_SW_I2C 
    GPIO_Init_Type gpio_init;
    gpio_init.Pins  = SWI2C1_SCL_PIN;
    gpio_init.PinMode  = GPIO_PinMode_Out_OpenDrain;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(SWI2C1_SCL_PORT, &gpio_init);
    GPIO_PinAFConf(SWI2C1_SCL_PORT, gpio_init.Pins, GPIO_AF_15); /* disable the alternative functions. */

    /* PC7 - I2C1_SDA. */
    gpio_init.Pins  = SWI2C1_SDA_PIN;
    gpio_init.PinMode  = GPIO_PinMode_Out_OpenDrain;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(SWI2C1_SDA_PORT, &gpio_init);
    GPIO_PinAFConf(SWI2C1_SDA_PORT, gpio_init.Pins, GPIO_AF_15); /* disable the alternative functions. */

    SWI2C1_SDA_HIGH; 
	SWI2C1_SCL_HIGH;
#endif    
}

#if I2C_MODE == USE_HARD_I2C  
/* Write data to target device, true to writing succeed, false to writing failed. */
bool BOARD_I2c1_Write(uint8_t txlen, uint8_t *txbuf)
{
    app_i2c_xfer.WaitTimes = APP_I2C_TIMEOUT_TIME;
    app_i2c_xfer.TxBuf = txbuf;
    app_i2c_xfer.TxLen = txlen;

    I2C_Enable(I2C1, true);  /* Disable I2C to clear tx fifo, and enabled I2C to perform the write operation again. */
    if ( false == I2C_MasterWriteBlocking(I2C1, &app_i2c_xfer) )
    {
        return false;
    }
    else
    {
        return true;
    }
}

/* Read data to target device, true to reading succeed, false to reading failed. */
bool BOARD_I2c1_Read(uint8_t rxlen, uint8_t *rxbuf)
{
    app_i2c_xfer.WaitTimes = APP_I2C_TIMEOUT_TIME;
    app_i2c_xfer.RxBuf = rxbuf;
    app_i2c_xfer.RxLen = rxlen;

    I2C_Enable(I2C1, true);  /* Disable I2C to clear tx fifo, and enabled I2C to perform the read operation again. */
    if ( false == I2C_MasterReadBlocking(I2C1, &app_i2c_xfer) )
    {
        return false;
    }
    else
    {
        return true;
    }
}
#elif I2C_MODE == USER_SW_I2C 

static void SwI2c_Delay_Us(int32_t us)
{
	app_swdelay_us(us);
}

static void SwI2c_Sda_Config_Output_mode(void)
{
    GPIO_Init_Type gpio_init;
    /* PC7 - I2C1_SDA. */
    gpio_init.Pins  = SWI2C1_SDA_PIN;
    gpio_init.PinMode  = GPIO_PinMode_Out_OpenDrain;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(SWI2C1_SDA_PORT, &gpio_init);
    GPIO_PinAFConf(SWI2C1_SDA_PORT, gpio_init.Pins, GPIO_AF_15); /* disable the alternative functions. */

	SWI2C1_SDA_HIGH;
}

static void SwI2c_Sda_Config_Input_mode(void)
{
    GPIO_Init_Type gpio_init;
    /* PC7 - I2C1_SDA. */
    gpio_init.Pins  = SWI2C1_SDA_PIN;
    gpio_init.PinMode  = GPIO_PinMode_In_PullUp;
    gpio_init.Speed = GPIO_Speed_50MHz;
    GPIO_Init(SWI2C1_SDA_PORT, &gpio_init);
    GPIO_PinAFConf(SWI2C1_SDA_PORT, gpio_init.Pins, GPIO_AF_15); /* disable the alternative functions. */

}

void SwI2c_Start(void)
{
    SWI2C1_SCL_LOW; 							//  先使SCL = 0, 为SDA上的电平改变做准备
    SwI2c_Delay_Us(2);
    SWI2C1_SDA_HIGH; 							//  SDA = 1
    SwI2c_Sda_Config_Output_mode();      		//  sda OD 初始化输出1,
    SWI2C1_SDA_HIGH; 							//  SDA = 1, 此时SDA的电平变化对通讯双方没有影响
    SwI2c_Delay_Us(2);
    SWI2C1_SCL_HIGH; 							//  SCL = 1
    SwI2c_Delay_Us(2);
    SWI2C1_SDA_LOW; 							//  SDA=0,产生下降沿,启动IIC通讯
    SwI2c_Delay_Us(2);
    SWI2C1_SCL_LOW;								//  SCL=0,为SDA上的电平改变做准备
    SwI2c_Delay_Us(2);
}

void SwI2c_Stop(void)							//停止信号
{
	SWI2C1_SCL_LOW ; 							//  先使SCL = 0, 为SDA上的电平改变做准备
    SwI2c_Delay_Us(2);
    SWI2C1_SDA_HIGH; 							//  SDA = 1
    SwI2c_Sda_Config_Output_mode();      		//  sda OD 初始化输出1,
    SWI2C1_SDA_HIGH;
    SwI2c_Delay_Us(2);
    SWI2C1_SDA_LOW; 							//  SDA=0,此时SDA的电平变化对通讯双方没有影响
    SwI2c_Delay_Us(2);
    SWI2C1_SCL_HIGH; 							//  SCL=1
    SwI2c_Delay_Us(2);
    SWI2C1_SDA_HIGH; 							//  SDA=1,结束IIC通讯
    SwI2c_Delay_Us(2);                        	//  SDA在结束后维持在高电平,如果有干扰脉冲产生而使得SDA
                                       			//  变低,则干扰过后会恢复高电平. 此时SCL如果因干扰而处于
    return;   
}

uint8_t SwI2c_Wait_Ack(void)						//等待应答信号：0-应答；1-非应答
{
    uint8_t uc_time = 0;
	SwI2c_Sda_Config_Input_mode(); 				//SDA定义为输入 

	SWI2C1_SDA_HIGH;
	SwI2c_Delay_Us(1); 
	SWI2C1_SCL_HIGH;
	SwI2c_Delay_Us(1);

    while (SWI2C1_SDA_READ)
    {
        uc_time++;
        if (uc_time > 250)
        {
            SwI2c_Stop();
            return 1;
        }
    }
	SWI2C1_SCL_LOW;
	return 0; 
} 

void SwI2c_Ack(void)					//产生 ACK 应答
{ 
    SWI2C1_SDA_HIGH; 					//  SDA = 1
    SwI2c_Sda_Config_Output_mode();     //  sda OD 初始化输出1,
    SWI2C1_SDA_HIGH; 					//  SDA输出高电平
    SWI2C1_SDA_LOW; 					//  清SDA="0",CPU发低电平确认信号,
    SwI2c_Delay_Us(2);
    SWI2C1_SCL_HIGH; 					//  置SCL="1", 产生上升沿,发送一位确认数据
    SwI2c_Delay_Us(2);
    SWI2C1_SCL_LOW; 					//  清SCL="0",为SDA上的电平改变做准备
    return;
}

void Swi2c_No_Ack(void)					//产生 NACK 非应答
{ 
    SWI2C1_SDA_HIGH; 					//  SDA = 1
    SwI2c_Sda_Config_Output_mode();    	//  sda OD 初始化输出1,
    SWI2C1_SDA_HIGH; 					//  置SDA=1, CPU发"高电平非应答确认"信号
    SwI2c_Delay_Us(2);
    SWI2C1_SCL_HIGH; 					//  置SCL="1", 产生上升沿,发送一位确认数据
    SwI2c_Delay_Us(2);
    SWI2C1_SCL_LOW; 					//  清SCL="0",为SDA上的电平改变做准备
    return;
} 

//IIC 发送一个字节
bool SwI2c_Write_Byte(uint8_t data)
{ 
    uint8_t m;                        //  SDA = 1
    SwI2c_Sda_Config_Output_mode(); //  sda OD 初始化输出1,

    for (m = 0; m < 8; m++)
    {
        SWI2C1_SCL_LOW; 			//  SCL=0,为SDA上的电平改变做准备
        SwI2c_Delay_Us(2);

        if (data & BIT7) 			//  由最高位开始发送
        {
            SWI2C1_SDA_HIGH;
        }
        else
        {
            SWI2C1_SDA_LOW;
        }

        SwI2c_Delay_Us(2);
        SWI2C1_SCL_HIGH; 			//  SCL="1",产生上升沿,发送一位数据
        SwI2c_Delay_Us(2);
        data <<= 1;
    }

    SWI2C1_SCL_LOW; 				//  清SCL="0",产生下降沿, 器件使SDA="0"
    SwI2c_Delay_Us(2);
    SwI2c_Sda_Config_Input_mode(); 	//  SDA改为输入,准备接收确认应答

    SWI2C1_SCL_HIGH;	 			//  SCL="1",让CPU在此期间读取SDA上的信号

    for (m = 0; m < 8; m++)
    {
        SwI2c_Delay_Us(2);

        if (SWI2C1_SDA_READ == 0)
        {
            SWI2C1_SCL_LOW; 		//  清SCL="0",为SDA上的电平改变做准备
            SwI2c_Delay_Us(2);
            return true; 			//  收到正确的低电平应答
        }
    }

	SWI2C1_SCL_LOW; 				//  清SCL="0",为SDA上的电平改变做准备
    return false;  
} 

//只写地址
uint8_t Write_Device_Addr(uint8_t addr)
{
	uint8_t read_ack = 0;
	SwI2c_Start();
	read_ack = SwI2c_Write_Byte(addr);
	SwI2c_Stop();
	return(read_ack);
}

//读一个字节
uint8_t SwI2c_Read_Byte()
{
    uint8_t m, data;

    SwI2c_Sda_Config_Input_mode(); 	//  SDA改为输入,准备接收数据
    data = 0;

    for (m = 0; m < 8; m++)
    {
        SWI2C1_SCL_LOW; 			//  SCL="0",产生下降沿, 器件串出一位数据
        SwI2c_Delay_Us(2);
        SWI2C1_SCL_HIGH; 			//  置SCL="1", 让CPU在此期间读取SDA上的信号
        SwI2c_Delay_Us(2);
        data <<= 1;

        if (SWI2C1_SDA_READ)
        {
            data |= BIT0;
        }
        else
        {
            data &= (~BIT0);
        }
    }

    SWI2C1_SCL_LOW; 				//  清SCL="0",为SDA上的电平改变做准备
    return data;
}


//在总线上搜寻挂载的器件地址
void SwI2c_Search_Device_Addr(void)
{
	uint8_t result = 0;
	uint8_t j = 0;
	for(j = 0;j < 128; j++)
	{
		if((j % 16) == 0)
		{
			printf("\r\n");
		}
		result = Write_Device_Addr(j << 1);
		if(result == true)
		{
			printf(" %X ",j << 1);//%X 十六进制输出，大写；%x 小写
		}
		else
		{
			printf(" -- ");
		}
	}
    printf("\r\n");
}

bool SwI2c_Device_Write_Data(uint8_t device_addr,uint8_t *reg_addr,
                                    uint16_t reg_len,const uint8_t *buf,uint8_t len)
{
   	SwI2c_Start();
    SwI2c_Write_Byte(device_addr);

	while (reg_len != 0)
    {
        if (SwI2c_Write_Byte(*reg_addr++) == false) //  发送一字节数据
        {
            SwI2c_Stop();
            return false;
        }
        reg_len--;
    }

    while (len != 0)
    {
        if (SwI2c_Write_Byte( *buf++) == false) //  发送一字节数据
        {
            SwI2c_Stop();
            return false;
        }
        len--;
    }

    SwI2c_Stop();
    return true;
}

bool SwI2c_Device_Read_Data(uint8_t device_addr,uint8_t *reg_addr,
                                    uint16_t reg_len, uint8_t *buf,uint8_t len)
{
    SwI2c_Start();
    SwI2c_Write_Byte(device_addr);
    while (reg_len != 0)
    {
        if (SwI2c_Write_Byte(*reg_addr++) == false) //  发送一字节数据
        {
            SwI2c_Stop();
            return false;
        }
        reg_len--;
    }

    SwI2c_Start();
    SwI2c_Write_Byte(device_addr + 1);

    while (1)
    {
        *buf++ = SwI2c_Read_Byte();					//  接收一字节
        len--;

        if (0 == len)
        {
            break;
        }
        SwI2c_Ack(); 								//  未读完,CPU发低电平确认应答信号,以便读取下8位数据
    }

    Swi2c_No_Ack(); 								//  已读完所有的数据,CPU发"高电平非应答确认"信号
    SwI2c_Stop();
    return true;
}


#endif